package eu.webhib.webblog.gui.controller;

import eu.webhib.frmwrk.jsf.base.EditBaseController;
import eu.webhib.frmwrk.jsf.utils.JsfUtil;
import eu.webhib.frmwrk.persistence.PersistenceMngr;
import eu.webhib.webblog.application.ApplMail;
import eu.webhib.webblog.domain.User;
import eu.webhib.webblog.gui.application.GuiApplication;
import eu.webhib.webblog.service.factory.ServiceFactory;
import eu.webhib.webblog.service.intf.UserService;
import javax.faces.bean.*;
import javax.faces.event.*;
import org.apache.log4j.Logger;

/**
 * Controller of the User Profile page
 */
@ManagedBean(name = "prof")
@ViewScoped
public class Profile extends EditBaseController {

   private static final Logger log = Logger.getLogger(Profile.class);
   private static UserService userService = ServiceFactory.getUserService();
   // User input data
   private String displayName;
   private String email;
   private String emailConfirmed;
   private String userName;
   private String passWord;
   private String passWordConfirm;
   //
   private User userLoaded;

   //
   // User input  ----------------------------------------------------------
   //
   public String getDisplayName() {
      return displayName;
   }

   public void setDisplayName(String displayName) {
      this.displayName = displayName;
   }

   public String getEmail() {
      return email;
   }

   public void setEmail(String email) {
      this.email = email;
   }

   public boolean isEmailConfirmed() {
      return emailConfirmed != null && email.equals(emailConfirmed);
   }

   public String getUserName() {
      return userName;
   }

   public void setUserName(String userName) {
      this.userName = userName;
   }

   public String getPassWord() {
      return null;
   }

   public void setPassWord(String passWord) {
      this.passWord = passWord;
   }

   public String getPassWordConfirm() {
      return null;
   }

   public void setPassWordConfirm(String passWordConfirm) {
      this.passWordConfirm = passWordConfirm;
   }

   //
   // Profile actions ----------------------------------------------------------------------
   //
   public void profileListener(ComponentSystemEvent event) {
      log.info("profileListener");
      if (!GuiApplication.isAuthenticated()) {
         JsfUtil.sendRedirect(GuiApplication.getLoginPageURI());
         return;
      }
      if (JsfUtil.isGet()) {
         loadUser();
         setInfoMessage("info_profile_new");
      }
   }

   public String saveAction() {
      log.info("saveAction");
      return new EditActionClosure() {

         @Override
         protected void run() {
            doProfileSaveAction();
         }
      }.start();
   }

   private void doProfileSaveAction() {
      // check if authenticated user is still logged in
      Long loggedinUserId = GuiApplication.getAuthenticationData().getAuthenticatedUserId();
      if (loggedinUserId == null) {
         JsfUtil.sendRedirect(GuiApplication.getLoginPageURI());
         return;
      }
      // check if loggedinUserId still exists and is enabled
      User user = userService.findId(loggedinUserId);
      if (user == null && user.isEnabled()) {
         // log out user forcible
         GuiApplication.getAuthenticationData().setAuthenticatedUser(null);
         JsfUtil.sendRedirect(GuiApplication.getLoginPageURI());
         return;
      }
      // if logged in user is not the same any more
      // or user data have changed at database since the GET request
      if (loggedinUserId == null
              || !loggedinUserId.equals(userLoaded.getId())
              || !user.getVersion().equals(userLoaded.getVersion())) {
         // reload user data and display error message
         loadUser();
         setErrorMessage("error_userdata_changed");
         return;
      }

      boolean dataChanged = false;
      boolean emailChanged = false;
      boolean credentialsChanged = false;

      // if user has changed data: check input data fields: displayName, email, userName
      if (!displayName.equals(user.getDisplayName())) {
         Register.checkDisplayName(displayName);
         dataChanged = true;
      }
      if (!email.equals(user.getEmail())) {
         Register.checkEmail(email);
         dataChanged = true;
         emailChanged = true;
      }
      if (!userName.equals(user.getUserName())) {
         Register.checkUserName(userName);
         dataChanged = true;
         credentialsChanged = true;
      }
      // check and compare password and confirmation password
      if (!passWord.isEmpty() || !passWordConfirm.isEmpty()) {
         Register.checkPasswords(passWord, passWordConfirm);
         dataChanged = true;
         credentialsChanged = true;
      }

      if (!dataChanged) {
         JsfUtil.sendRedirect(GuiApplication.getHistroyPageURI());
         return;
      }

      // if there was an input error
      if (!isInputOk()) {
         return;
      }

      // change user at database
      if ((userLoaded = updateUser(user)) == null) {
         // if there was an error at database write operation
         setFatalMessage("fatal_database_write");
         return;
      }

      // send confirmation email if email has changed to new email address
      if (emailChanged) {
         if (!ApplMail.sendUserMail(
                 user.getEmail(),
                 "info_profile_emailchange_mail",
                 "info_profile_emailchange_subject",
                 GuiApplication.emailConfirmPage,
                 user)) {
            // if there was an error at mail transmission
            setFatalMessage("fatal_sendmail");
            PersistenceMngr.setRollbackTransaction();
            return;
         }
      }
      // send status email if userName or passWord has changed
      if (credentialsChanged) {
         if (!ApplMail.sendUserMail(
                 user.getEmailConfirmed(),
                 "info_profile_credentialschange_mail",
                 "info_profile_credentialschange_subject",
                 null,
                 user)) {
            // if there was an error at mail transmission
            setFatalMessage("fatal_sendmail");
            PersistenceMngr.setRollbackTransaction();
            return;
         }
      }
      setInfoMessage("info_profile_ok");
      if (emailChanged) {
         appendMessageText("info_profile_emailchange", email);
      }
   }

   private User updateUser(User user) {
      log.info("updateUser");
      try {
         user.changeData(displayName, email, userName, passWord);
         user = userService.update(user);
         log.info("user changed, userName:" + userName);
      } catch (Throwable t) {
         log.error("updateUser", t);
         return null;
      }
      return user;
   }

   // Cancel Profile page
   public String cancelAction() {
      JsfUtil.sendRedirect(GuiApplication.getHistroyPageURI());
      return null;
   }

   private void loadUser() {
      userLoaded = userService.findId(GuiApplication.getAuthenticationData().getAuthenticatedUserId());
      this.displayName = userLoaded.getDisplayName();
      this.email = userLoaded.getEmail();
      this.emailConfirmed = userLoaded.getEmailConfirmed();
      this.userName = userLoaded.getUserName();
      this.passWord = this.passWordConfirm = null;
   }
}
